from imutils import paths
import numpy as np
import imutils
import cv2
# https://www.pyimagesearch.com/2018/12/17/image-stitching-with-opencv-and-python/

path_input_directory = "images/scottsdale"
path_output_directory = "output.png"
args_crop = 1

# 这个脚本包含技巧，可以提取缝合图像的ROI，以获得美观的结果。

# 抓取输入图像的路径并初始化图像列表
print("[INFO] loading images...")
imagePaths = sorted(list(paths.list_images(path_input_directory)))
images = []
# 循环遍历图像路径，加载每个图像路径，然后将它们添加到我们的图像中以拼接列表
for imagePath in imagePaths:
    image = cv2.imread(imagePath)
    images.append(image)

# 初始化OpenCV的图像拼接器对象，然后执行图像拼接
print("[INFO] stitching images...")
stitcher = cv2.createStitcher() if imutils.is_cv3() else cv2.Stitcher_create()
(status, stitched) = stitcher.stitch(images)

# 如果状态为“0”，则OpenCV成功执行了图像拼接
if status == 0:
    # 检查我们是否应该从拼接图像中裁剪出最大的矩形区域
    # 这个if可以不要，不要就会变成简单版本
    if args_crop > 0:
        # 在拼接的图像周围创建一个10像素的边框
        print("[INFO] cropping...")
        stitched = cv2.copyMakeBorder(stitched, 10, 10, 10, 10,
                                      cv2.BORDER_CONSTANT, (0, 0, 0))
        # 将拼接的图像转换为灰度并对其进行阈值处理
        # 使所有大于0的像素都设置为255（前景），而所有其他像素保持为0（背景）
        gray = cv2.cvtColor(stitched, cv2.COLOR_BGR2GRAY)
        thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY)[1]
        # 在阈值图像中找到所有外部轮廓，然后找到最大轮廓，该轮廓将为拼接图像的轮廓
        cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
                                cv2.CHAIN_APPROX_SIMPLE)
        cnts = imutils.grab_contours(cnts)
        c = max(cnts, key=cv2.contourArea)
        # 为遮罩分配内存，该遮罩将包含拼接图像区域的矩形边界框
        mask = np.zeros(thresh.shape, dtype="uint8")
        (x, y, w, h) = cv2.boundingRect(c)
        cv2.rectangle(mask, (x, y), (x + w, y + h), 255, -1)
        # 创建蒙版的两个副本：
        # 一个充当实际的最小矩形区域
        # 一个充当计数器，以删除需要去除多少像素以形成最小矩形区域
        minRect = mask.copy()
        sub = mask.copy()

        # 继续循环直到减法图像中没有剩余非零像素
        while cv2.countNonZero(sub) > 0:
            # 侵蚀最小矩形蒙版，然后从最小矩形蒙版中减去阈值图像，这样就可以算出是否还有非零像素
            minRect = cv2.erode(minRect, None)
            sub = cv2.subtract(minRect, thresh)

        # 在最小矩形蒙版中找到轮廓，然后提取边界框（x，y）坐标
        cnts = cv2.findContours(minRect.copy(), cv2.RETR_EXTERNAL,
                                cv2.CHAIN_APPROX_SIMPLE)
        cnts = imutils.grab_contours(cnts)
        c = max(cnts, key=cv2.contourArea)
        (x, y, w, h) = cv2.boundingRect(c)

        # 使用边界框坐标提取最终的拼接图像
        stitched = stitched[y:y + h, x:x + w]

    # 将输出的拼接图像写入磁盘
    cv2.imwrite(path_output_directory, stitched)

    # 在屏幕上显示输出的拼接图像
    cv2.imshow("Stitched", stitched)
    cv2.waitKey(0)

# 如果状态不为“0”，拼接可能失败，可能是由于未检测到足够的关键点
else:
    print("[INFO] image stitching failed ({})".format(status))
